資訊大爆炸。
有時候我們瀏覽技術文章,不一定真的是想學深奧的高級技術。
然而劣質低端的文章充斥著,則會降低我們學習的效率、甚至變成噪音與雜訊,干擾我們的思緒。
因此針對某些洗文或是質量很低的作者,我們必須列為思想犯,
否則會降低閱讀質量,平白浪費自己的時間、平台的版面、上網的電力、看到垃圾資訊的副作用等等....
如果有個思想審查警衛可以:去除那些垃圾低端,稱不上技術文章的雜訊。
以確保未來瀏覽文章的時候,不會再被洗文打擾,
也可以針對不喜歡的主題去封鎖,讓時間與精神更能專注於自己想要學的資訊。
阻止一些垃圾就是喜歡把自己尚未整理的白痴內容一直丟上來,
什麼都還不懂,把技術文章當成個人日記簿,寫一堆自我囈語、無病呻吟,
每天大量狂發文章,昭告天下以為這就是努力,欺騙自己也浪費別人的人生。
此截圖僅是腳本示範,跟其使用者無關,
本人沒有任何覺得此使用者發的文章是差勁的意味,我認為非常上進、值得學習。
此圖也只是隨機挑user使用,純粹作為範例用途,不代表我個人意見。
https://greasyfork.org/zh-TW/scripts/477283-%E6%80%9D%E6%83%B3%E7%8A%AF%E5%B0%81%E6%AE%BA
鄭重聲明,這個示範真的毫無任何私人意味,此腳本也只是針對不同的主題去隱藏,
例如我想學python就不想看到JS的文章,因此使用此工具幫忙隱藏罷了。
取名做思想警察、比喻成清除垃圾等都只是文學上的趣味。
請勿當真Ꮚ・ꈊ・Ꮚ
這次的技術可說比較難,認真難很多!但是趣味性以及功能性是無比的超越!
可以說幾乎是我寫系列文以來,最頂、最派的一篇!
不過很多觀念已經出現過,在【前端小試身手】系列裡面,每次的腳本都是主打實用,
因此cookie或localstorage這種技術當然都會運用到。
// ==UserScript==
// @license MIT
// @name 👮思想犯封殺
// @namespace http://tampermonkey.net/
// @version 0.1
// @description 把廢文製造機轟出去
// @author You
// @match https://ithelp.ithome.com.tw/articles*
// @match https://ithelp.ithome.com.tw/users/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=ithome.com.tw
// @grant none
// @run-at document-end
// ==/UserScript==
let URL = window.location.href;
let ArticleSite = "https://ithelp.ithome.com.tw/articles?tab=tech"
let UserSite = "https://ithelp.ithome.com.tw/users/"
// 判斷URL的開頭部分
if (URL.startsWith(ArticleSite)) {
//文章頁執行清理垃圾程序
CleanGarbage();
} else if (URL.startsWith(UserSite)) {
UserCheck();
} else {
console.log("這邊不執行腳本");
}
// 餅乾儲存的機制函數-------------------------------------------------
function setListInCookie(list) {
document.cookie = 'myList=' + JSON.stringify(list) + '; expires=Wed, 31 Dec 2099 23:59:59 GMT;';
}
// 從 Cookie 中獲取 list
function getListFromCookie() {
var cookieValue = document.cookie.replace(/(?:(?:^|.*;\s*)myList\s*\=\s*([^;]*).*$)|^.*$/, "$1");
return JSON.parse(cookieValue) || [];
}
function CleanGarbage(){
// 從本地存儲中獲取數據
var myListData = localStorage.getItem("myList");
// 解析數據到變量 list
var list = myListData ? JSON.parse(myListData) : [];
//list = getListFromCookie()||[]; // 儲存要刪除的字符串名單
// 找到所有CLASS是"qa-list__info-link"的<a>元素
var linkElements = document.querySelectorAll('.qa-list__info-link');
var removedCount = 0; // 初始化已清除的垃圾數量
for (var j = 0; j < list.length; j++) {
// 遍歷這些<a>元素,確保文本內容包含"伍貳捌",然後刪除其父元素
for (var i = 0; i < linkElements.length; i++) {
if (linkElements[i].textContent.includes(list[j])) {
// 開始向上查找父元素
var parentElement = linkElements[i].parentElement;
while (parentElement) {
// 如果找到具有"classname"為"qa-list"的<div>元素,則刪除它
if (parentElement.classList.contains('qa-list')) {
parentElement.remove();
removedCount++; // 增加清除的數量
console.warn('抓到"'+list[j]+'"這位思想犯');
break; // 找到並刪除後,結束循環
}
parentElement = parentElement.parentElement;
}
}
}
if (removedCount>0){
// 顯示已清除的垃圾數量
console.log('已清除他的 ' + removedCount + ' 篇垃圾');}
removedCount=0;
}
}
//-------------------------------------------------------
// 為了防止五百八改名,我們針對他的ID去ajax得到他最新的名稱
function FindBitch() {
// 使用 Fetch API 獲取指定 URL 的內容
return fetch("https://ithelp.ithome.com.tw/users/20163468")
.then(response => response.text())
.then(data => {
// 創建一個臨時 div 元素以容納頁面內容
var tempDiv = document.createElement("div");
tempDiv.innerHTML = data;
// 查找 class 為 "profile-header__name" 的元素
var profileNameElement = tempDiv.querySelector(".profile-header__name");
if (profileNameElement) {
// 刪除元素內的所有 <span> 元素
var spanElements = profileNameElement.querySelectorAll("span");
spanElements.forEach(function(span) {
span.remove();
});
// 讀取元素的文本內容,去掉前導和尾隨空格
var text = profileNameElement.textContent.trim();
// 返回處理後的文本內容
return text;
} else {
return "未找到元素";
}
})
.catch(error => {
console.error("發生錯誤: " + error);
return "發生錯誤";
});
}
//-------------------------------------------------------
function UserCheck(){
//轉換資料從餅乾到localstorage
var currentCookieValue = getCookie("myList");
// 2. 存儲數據到本地存儲
if (currentCookieValue) {
var list = JSON.parse(currentCookieValue);
// 存儲到本地存儲
localStorage.setItem("myList", JSON.stringify(list));
}else{
FindBitch()
.then(text => {
let FirstKill = [text];
setListInCookie(FirstKill);
})
.catch(error => {
console.error("找不到五百八:", error);
});
}
// 刪除不需要的ID
document.querySelector('.profile-header__account').remove();
//封殺按鈕-------------------------------------------------
// 找到具有class為"profile-header__right"的元素
var profileRightElement = document.querySelector('.profile-header__right');
var pullRightElement = profileRightElement.querySelector('.pull-right');
// 創建一個新按鈕元素
var BlockBtn = document.createElement('button');
BlockBtn.textContent = '封殺';
// 添加樣式和類名到按鈕
BlockBtn.style.marginTop = '10px';
BlockBtn.style.width = '100%';
BlockBtn.className = 'btn btn-trace trace_btn_border BlockBtn';
// 將按鈕元素添加到"pull-right"元素內部
pullRightElement.appendChild(BlockBtn);
// 通緝犯名單的cookie------------------------------------------------
// 從 Cookie 中加載 list(例如,頁面加載時)
list = getListFromCookie()||[];
let UserBlock = document.querySelector('.profile-header__name');
let text = UserBlock.textContent.trim();
// 如果使用者已經在封殺名單內的判斷,已存在或不存在
if (list.includes(text)) {
BlockStart(BlockBtn);
}
else
{
// 針對封殺按鈕進行監聽事件
BlockBtn.addEventListener('click', function() {
list.push(text);
setListInCookie(list);
//先加入到名單內,然後再執行封殺事件
BlockStart();
// 輸出到控制台
console.log('黑名單新增:' + text);
//本地儲存機制-----------------------------
let currentCookieValue = getCookie("myList");
let list2 = JSON.parse(currentCookieValue);
// 存儲到本地存儲
localStorage.setItem("myList", JSON.stringify(list2));
});
}
}
// ------------------------------------------------
//封殺事件的函數
function BlockStart(){
let BlockBtn = document.querySelector('.BlockBtn');
BlockBtn.textContent = '已封殺';
BlockBtn.disabled = true;
BadText();
BadImg();
}
//封殺事件函數裡面的細項函數
function BadText(){
// 標記這傢夥是垃圾-------------------------------------------------
let UserBlock = document.querySelector('.profile-header__name');
let newHeading = document.createElement('h1');
newHeading.textContent = '思想通緝犯';
// 把思想通緝犯這幾個大字加上去
UserBlock.parentElement.insertBefore(newHeading, UserBlock);
UserBlock.style.textDecoration = "line-through";
UserBlock.style.color = "red";
}
function BadImg(){
//圖片進行網點作業XD-------------------------------------------------
var originalImage = document.querySelector('.profile-header__avatar');
// 創建一個包含交叉紅線的覆蓋層 <div> 元素
var overlayDiv = document.createElement('div');
overlayDiv.style.position = 'absolute';
overlayDiv.style.width = '150px';
overlayDiv.style.height = '150px';
overlayDiv.style.background = 'linear-gradient(45deg, black 50%, transparent 50%), linear-gradient(-45deg, black 50%, transparent 50%)';
overlayDiv.style.backgroundSize = '5px 5px, 5px 5px';
overlayDiv.style.backgroundPosition = '0 0, 0 2px';
// 將覆蓋層疊加到圖片上
originalImage.parentNode.appendChild(overlayDiv);
// 設置覆蓋層的位置,以與原始圖像對齊
overlayDiv.style.top = originalImage.offsetTop + 'px';
overlayDiv.style.left = originalImage.offsetLeft + 'px';
// 設置覆蓋層的z-index,以確保它在圖片上方
overlayDiv.style.zIndex = '2';
}
這個腳本開發足足花了我一整個晚上,將近八小時之久。
有趣的是,其中為了進行測試才選某些user當作隱藏對象,否則腳本執行上會出錯。
細心的人若觀察原始碼,也會發現裡面有個firstKill,
那是必須要的段落,先設置好cookie的首要內容物,才有辦法繼續操作下去( ิ◕㉨◕ ิ)
也就是初始化的概念XD
另一個有趣的點是,為了防止使用者改名導致腳本出錯,我甚至不惜再寫一段ajax,
去更新一下ID,這樣不管人家怎麼改,都逃不了,
要改成「別抓我」也沒用,這個腳本都還是可以run。
我只能說這篇是自從「備份IT幫發文、一眼全覽」最強的JS教學文章!
超派,真的不騙( メ∀・)
有些人喜歡看前端小試身手,有些人喜歡前端動手玩創意;
其實這兩個系列的本質都是JS的教學,是可以互相連接的,但也有很多不同的重心。
這個系列就是以腳本為主,重點在於創意與發想,打到使用者痛點。
【前端動手玩創意】則是以建構網站為起點,
任何元素與概念都會變成網頁上的一部分,算是比較基礎工的建立。
如果對JS的強大感興趣,那麼可以把這兩個系列交互看,反覆的閱讀、實際動手操作,
這樣一來的學習非常踏實,甚至比YT學習都來的高效率、實際。
尤其此系列都是原創發想的腳本,當然超強!
喜歡記得關注,未來還有更多超酷的前端內容可以玩,下課⧸⎩⎠⎞͏(・∀・)⎛͏⎝⎭⧹